package net.sinodata.smartframework.schedulejob.base;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SchedulerMetaData;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Description: 定时任务核心管理类
 * 
 * @author: yinliangyun
 * @date: 2021-5-18
 */
public class ScheduleJobManager {
	
	private static final Logger logger = LoggerFactory.getLogger(ScheduleJobManager.class);

	private static ScheduleJobManager scheduleJobManager = new ScheduleJobManager();

	private Scheduler scheduler = null;
	
	private static final String GROUP_NAME = "group1";

	private ScheduleJobManager() {
		SchedulerFactory schedulerFactory = new StdSchedulerFactory();
		try {
			scheduler = schedulerFactory.getScheduler();// 创建调度器
		} catch (SchedulerException e) {
			logger.error("ScheduleJobManager ScheduleJobManager SchedulerException" + "_" + e.getMessage(), e);
		}
	}

	public static ScheduleJobManager getInstance() {// 单例
		return scheduleJobManager;
	}

	// 启动定时任务
	public synchronized void startJob(Class<? extends AbstractScheduleJob> clazz, String jobName, String cronExpression, Integer multiRunFlag) {
		JobDetail job = JobBuilder.newJob(clazz).withIdentity(jobName + "-job", GROUP_NAME).build();// 创建任务
		
		job.getJobDataMap().put("multiRunFlag", (multiRunFlag == null || multiRunFlag == 0) ? true : false);// 是否允许多线程运行

		// 创建触发器
		CronTrigger trigger = TriggerBuilder.newTrigger()
				.withIdentity(jobName + "-trigger", GROUP_NAME)
				.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
				.build();
		try {
			Date date = scheduler.scheduleJob(job, trigger);//任务，触发器
			logger.info("ScheduleJobManager startJob : {},  has been scheduled to run at : {},  and repeat based on expression : {}", job.getKey(), date, trigger.getCronExpression());
		} catch (SchedulerException e) {// 任务启动异常
			logger.error("ScheduleJobManager startJob SchedulerException" + "_" + e.getMessage(), e);
			throw new ScheduleJobException("定时任务（" + job.getKey().toString() + "）启动异常");
		}
		standby();//待机
		start();// 启动
	}
	
	public ScheduleJobStatus getScheduleJobStatus(String jobName) {// 获取定时任务状态
		ScheduleJobStatus status = null;
		try {
			Map<String, ScheduleJobStatus> allJobStatus = getAllScheduleJobStatus();// 获取所有定时任务状态
			if (allJobStatus.containsKey(jobName + "-job")) {// 判断定时任务是否存在
				status = allJobStatus.get(jobName + "-job");// 获取定时任务状态
			}
		} catch (Exception e) {
			logger.error("ScheduleJobManager getScheduleJobStatus Exception" + "_" + e.getMessage(), e);
			throw new ScheduleJobException("获取定时任务（" + jobName + "）状态异常");
		}
		if (null == status) {
			return new ScheduleJobStatus(null, jobName + "-job", null, null);
		}
		return status;
	}
	
	public Map<String, ScheduleJobStatus> getAllScheduleJobStatus() {// 获取所有定时任务状态
		Map<String, ScheduleJobStatus> allJobStatus = new HashMap<String, ScheduleJobStatus>();
		try {
			Set<JobKey> keys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(GROUP_NAME));
			for (Iterator<JobKey> it = keys.iterator(); it.hasNext();) {
				JobKey jobKey = it.next();
				JobDetail jobDetail = scheduler.getJobDetail(jobKey);
				List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
				Date date = null;
				if (triggers.size() > 0) {
					Trigger trigger = triggers.get(0);
					date = trigger.getNextFireTime();
				}
				allJobStatus.put(jobDetail.getKey().getName(),
						new ScheduleJobStatus(jobDetail.getKey(), jobDetail.getKey().getName(), date, null));
			}
		} catch (Exception e) {
			logger.error("ScheduleJobManager getAllScheduleJobStatus Exception" + "_" + e.getMessage(), e);
			throw new ScheduleJobException("获取所有定时任务状态异常");
		}
		logger.info("ScheduleJobManager getAllScheduleJobStatus allJobStatus : {}", allJobStatus.toString());
		return allJobStatus;
	}
	
	public synchronized void start() {// 启动
		try {
			scheduler.start();
		} catch (SchedulerException e) {
			logger.error("ScheduleJobManager start SchedulerException" + "_" + e.getMessage(), e);
			throw new ScheduleJobException("启动定时任务异常");
		}
	}
	
	public synchronized void standby() {// 待机
		try {
			scheduler.standby();
		} catch (SchedulerException e) {
			logger.error("ScheduleJobManager standby SchedulerException" + "_" + e.getMessage(), e);
			throw new ScheduleJobException("启动定时任务异常");
		}
	}

	public void distory() {// 销毁
		if (scheduler != null) {
			try {
				scheduler.shutdown(true);
				SchedulerMetaData metaData = scheduler.getMetaData();
				logger.info("ScheduleJobManager distory JobsExecuted : {} jobs." + metaData.getNumberOfJobsExecuted());
			} catch (SchedulerException e) {
				logger.error("ScheduleJobManager distory shutdown scheduler SchedulerException" + "_" + e.getMessage(), e);
				throw new ScheduleJobException("关闭定时任务异常");
			}
		}
	}

	public void stopJob(String jobName) {// 停止定时任务
		Map<String, ScheduleJobStatus> allJobStatus = getAllScheduleJobStatus();
		ScheduleJobStatus scheduleJobStatus = allJobStatus.get(jobName + "-job");
		try {
			scheduler.deleteJob(scheduleJobStatus.getJobKey());
			logger.info("ScheduleJobManager stopJob jobName : {} success." + jobName);
		} catch (SchedulerException e) {
			logger.error("ScheduleJobManager stopJob SchedulerException" + "_" + e.getMessage(), e);
			throw new ScheduleJobException("停止定时任务异常");
		}
	}

}
